2023/12/233469字符
并发
线程可以理解为轻量级的进程
协程(微线程)可以理解为轻量级的线程
协程的优点:创建上百万个而不会导致系统的资源衰竭;线程和进程最多创建不会超过一万个
goroutine
- 封装 main 函数的 goroutine 称为主 goroutine;
- 申请每一个 goroutine 所能申请的栈空间的最大尺寸。在 32 位的计算机系统中最大尺寸是 256MB,64 位的系统中尺寸为 1GB。如果某个 goroutine 的栈空间大于这个限制,那么运行时系统就会引发一个栈溢出的运行时恐慌,随后这个 go 程序也会被终止。
- 初始化:
- 创建一个特殊的 defer 语句,用于在主 goroutine 退出时做必要的善后处理(主 goroutine 也可能非正常结束);
- 启动专用于在后台清扫内存垃圾的 goroutine,并设置 GC 可用的标识;
- 执行 main 包中的 init 函数;
- 执行 main 函数,检查主 goroutine 是否引发了运行时恐慌,并进行必要的处理,最后主 goroutine 会结束自己以及当前进程的运行。
goroutine 底层使用 coroutine 实现并发
- 用户空间,避免了内核态和用户态的切换导致的成本;
- 可以由语言和框架进行调度;
- 更小的栈空间允许创建大量的实例。
package main
import (
"fmt"
"time"
)
func main() {
go numbers() // go 开启新的协程
go alphabets()
time.Sleep(3000 * time.Millisecond) // 协程守护
fmt.Println("end")
}
func numbers() {
for i := 0; i <= 5; i++ {
time.Sleep(250 * time.Millisecond)
fmt.Printf("%d", i)
}
}
func alphabets() {
for i := 'a'; i < 'e'; i++ {
time.Sleep(400 * time.Millisecond)
fmt.Printf("%c", i)
}
}
//--> 0a12b3c45dend
模拟抢票
不要以共享内存的方式去通信,而是以通信的方式共享内存。保证数据安全
互斥锁
- 在改变数据的情况下,不能做任何操作
package main
import (
"fmt"
"sync"
"time"
)
var ticket = 10 // 总票数
var wg sync.WaitGroup // 同步等待对象
var mutex sync.Mutex // 创建锁
func main() {
wg.Add(2)
go saleTickets("通道1")
go saleTickets("通道2")
wg.Wait() // 等待计算器的值为 0
fmt.Println("end")
}
func saleTickets(name string) {
for {
mutex.Lock() // 加锁
if ticket <= 0 {
fmt.Println("not have")
mutex.Unlock() // 解锁
break
}
time.Sleep(time.Millisecond)
fmt.Println(name, ticket)
ticket--
mutex.Unlock()
}
wg.Done() // 计数器 -1
}
读写锁
- 读是可以随便读的,多个 goroutine 同时读
- 写的时候啥也不能干,不能读也不能写
package main
import (
"fmt"
"sync"
"time"
)
var rwMutex *sync.RWMutex // 创建锁
var wg *sync.WaitGroup // 同步等待对象
func main() {
rwMutex = new(sync.RWMutex)
wg = new(sync.WaitGroup)
wg.Add(4)
go readData(1)
go writeData(1)
go readData(2)
go writeData(2)
wg.Wait()
fmt.Println("end")
}
func readData(num int) {
fmt.Println(num, "read start")
rwMutex.RLock() // 读操作上锁
fmt.Println(num, "reading...")
time.Sleep(1 * time.Second)
rwMutex.RUnlock() // 读操作解锁
fmt.Println(num, "read over")
wg.Done()
}
func writeData(num int) {
fmt.Println("write start")
rwMutex.Lock() // 写操作上锁
fmt.Println("writing...")
time.Sleep(1 * time.Second)
rwMutex.Unlock() // 写操作解锁
fmt.Println("write over")
wg.Done()
}